﻿///
/// Pamela.Logic.Imps
///
namespace Pamela.Logic.Imps.Mvc
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Text;

    using Pamela.Logic.Helpers;
    using Pamela.Logic.Imps.Base;    
    using Pamela.Logic.Properties;

    internal class MvcViewBuilder : BaseBuilder
    {
        string index_source;
        string add_source;
        string edit_source;

        bool includeMasterPage;
        string layout;

        private string TargetDirectory;

        public MvcViewBuilder(Assembly assembly, BuilderInfo info, string layerName)
            : base(assembly, info, layerName)
        {
            index_source = SourceDirectory + "index.template";
            add_source = SourceDirectory + "add.template";
            edit_source = SourceDirectory + "edit.template";

            this.includeMasterPage = false;

            TargetDirectory = this.builderInfo.SolutionInnerDirectory + "\\" + builderInfo.RootNamespace + ".App\\Views\\" + this.builderInfo.SelectedModel;
            Directory.CreateDirectory(TargetDirectory);
        }

        public override void Build()
        {
            GenerateIndexViewCode();
            GenerateAddViewCode();
            GenerateEditViewCode();
        }

        private string GenerateLayoutTemplate()
        {
            if (includeMasterPage)
            {
                return "\tLayout = " + @"""" + layout + @""";";
            }

            return string.Empty;
        }

        private string GenerateHeaderTemplate()
        {
            var result = new StringBuilder();
            var type = this.assembly.GetType(this.builderInfo.SharedLayerNamespace + ".Models." + this.builderInfo.SelectedModel);

            foreach (var prop in type.GetProperties())
            {
                if (prop.GetMethod.IsVirtual || IsPrimaryKey(prop.Name))
                {
                    // skip to next property
                    continue;
                }

                if (!prop.PropertyType.Name.StartsWith(this.builderInfo.RootNamespace))
                {
                    result.Append("\t\t<th>");
                    result.Append("\r\n");
                    if (!IsForeignKey(prop.Name))
                    {
                        result.Append("\t\t\t@Html.DisplayNameFor(m => m." + prop.Name + ")");
                    }
                    else
                    {
                        result.Append("\t\t\t@Html.DisplayNameFor(m => m." + RemoveId(prop.Name) + "." + RemoveId(prop.Name) + "Name)");
                    }
                    result.Append("\r\n");
                    result.Append("\t\t</th>");
                    result.Append("\r\n");
                }
            }

            return result.ToString();
        }

        private string GenerateDataTemplate()
        {
            var result = new StringBuilder();
            var type = base.assembly.GetType(this.builderInfo.SharedLayerNamespace + ".Models." + this.builderInfo.SelectedModel);

            foreach (var prop in type.GetProperties())
            {
                if (prop.GetMethod.IsVirtual || IsPrimaryKey(prop.Name))
                {
                    // skip to next property
                    continue;
                }

                if (!prop.PropertyType.Name.StartsWith(this.builderInfo.RootNamespace))
                {
                    result.Append("\t\t<td>");
                    result.Append("\r\n");
                    if (!IsForeignKey(prop.Name))
                    {
                        result.Append("\t\t\t@Html.DisplayFor(m => item." + prop.Name + ")");
                    }
                    else
                    {
                        result.Append("\t\t\t@Html.DisplayFor(m => item." + RemoveId(prop.Name) + "." + RemoveId(prop.Name) + "Name)");
                    }
                    result.Append("\r\n");
                    result.Append("\t\t</td>");
                    result.Append("\r\n");
                }
            }

            return result.ToString();
        }

        private string GenerateAddFieldsTemplate()
        {
            var result = new StringBuilder();
            var type = base.assembly.GetType(this.builderInfo.SharedLayerNamespace + ".Models." + this.builderInfo.SelectedModel);

            foreach (var prop in type.GetProperties())
            {
                if (prop.GetMethod.IsVirtual)
                {
                    // skip to next property
                    continue;
                }

                if (prop.Name.ToLower() != "id" && prop.Name.ToLower() != "id" && prop.Name.ToLower() != this.builderInfo.SelectedModel.ToLower() + "id")
                {
                    result.Append("\t\t<div class=" + @"""editor-label"">");
                    result.Append("\r\n");
                    result.Append("\t\t\t@Html.LabelFor(m => m." + prop.Name + ")");
                    result.Append("\r\n");
                    result.Append("\t\t</div>");
                    result.Append("\r\n");
                    result.Append("\t\t<div class=" + @"""editor-field"">");
                    result.Append("\r\n");

                    string id = prop.Name.Substring(prop.Name.Length - 2);

                    if (id.ToLower() != "id")
                        result.Append("\t\t\t@Html.EditorFor(m => m." + prop.Name + ")");
                    else
                        result.Append("\t\t\t" + @"@Html.DropDownList(""" + prop.Name + @""", String.Empty)");

                    result.Append("\r\n");
                    result.Append("\t\t\t@Html.ValidationMessageFor(m => m." + prop.Name + ")");
                    result.Append("\r\n");
                    result.Append("\t\t</div>");
                    result.Append("\r\n");
                }
            }
            return result.ToString();
        }

        private string GenerateEditFieldsTemplate()
        {
            var result = new StringBuilder();
            var type = base.assembly.GetType(this.builderInfo.SharedLayerNamespace + ".Models." + this.builderInfo.SelectedModel);

            foreach (var prop in type.GetProperties())
            {
                if (prop.GetMethod.IsVirtual)
                {
                    // skip to next property
                    continue;
                }

                if (prop.Name.ToLower() == "id" || prop.Name.ToLower() == this.builderInfo.SelectedModel.ToLower() + "id")
                {
                    result.Append("\t\t@Html.HiddenFor(m => m." + prop.Name + ")");
                    result.Append("\r\n");
                }
                else
                {
                    result.Append("\t\t<div class=" + @"""editor-label"">");
                    result.Append("\r\n");
                    result.Append("\t\t\t@Html.LabelFor(m => m." + prop.Name + ")");
                    result.Append("\r\n");
                    result.Append("\t\t</div>");
                    result.Append("\r\n");
                    result.Append("\t\t<div class=" + @"""editor-field"">");
                    result.Append("\r\n");

                    string id = prop.Name.Substring(prop.Name.Length - 2);

                    if (id.ToLower() != "id")
                        result.Append("\t\t\t@Html.EditorFor(m => m." + prop.Name + ")");
                    else
                        result.Append("\t\t\t" + @"@Html.DropDownList(""" + prop.Name + @""", String.Empty)");

                    result.Append("\r\n");
                    result.Append("\t\t\t@Html.ValidationMessageFor(m => m." + prop.Name + ")");
                    result.Append("\r\n");
                    result.Append("\t\t</div>");
                    result.Append("\r\n");
                }
            }
            return result.ToString();
        }

        private void GenerateIndexViewCode()
        {
            var target = TargetDirectory + "\\Index.cshtml";

            using (StreamReader template = new StreamReader(index_source))
            using (StreamWriter output = new StreamWriter(target))
            {
                while (template.Peek() >= 0)
                {
                    string buffer = template.ReadLine();

                    buffer = buffer.Replace(Resources.NamespaceBal, this.builderInfo.BusinessLayerNamespace);
                    buffer = buffer.Replace(Resources.Namespace, this.builderInfo.RootNamespace);
                    buffer = buffer.Replace(Resources.SelectedModel, this.builderInfo.SelectedModel);
                    buffer = buffer.Replace(Resources.SelectedModelSmallCaps, this.builderInfo.SelectedModel.ToLower());
                    buffer = buffer.Replace(Resources.Entity, pluralizationService.Pluralize(this.builderInfo.SelectedModel));
                    buffer = buffer.Replace(Resources.ViewBagHeaderTemplate, this.GenerateHeaderTemplate());
                    buffer = buffer.Replace(Resources.ViewBagDataTemplate, this.GenerateDataTemplate());
                    buffer = buffer.Replace(Resources.ViewBagLayoutTemplate, this.GenerateLayoutTemplate());

                    output.WriteLine(buffer);
                }
            }
        }

        private void GenerateAddViewCode()
        {
            var target = TargetDirectory + "\\Add.cshtml";

            using (StreamReader template = new StreamReader(add_source))
            using (StreamWriter output = new StreamWriter(target))
            {
                while (template.Peek() >= 0)
                {
                    string buffer = template.ReadLine();

                    buffer = buffer.Replace(Resources.NamespaceBal, this.builderInfo.BusinessLayerNamespace);
                    buffer = buffer.Replace(Resources.Namespace, this.builderInfo.RootNamespace);
                    buffer = buffer.Replace(Resources.SelectedModel, this.builderInfo.SelectedModel);
                    buffer = buffer.Replace(Resources.SelectedModelSmallCaps, this.builderInfo.SelectedModel.ToLower());
                    buffer = buffer.Replace(Resources.Entity, pluralizationService.Pluralize(this.builderInfo.SelectedModel));
                    buffer = buffer.Replace(Resources.ViewBagFieldsTemplate, this.GenerateAddFieldsTemplate());
                    buffer = buffer.Replace(Resources.ViewBagLayoutTemplate, this.GenerateLayoutTemplate());

                    output.WriteLine(buffer);
                }
            }
        }

        private void GenerateEditViewCode()
        {
            var target = TargetDirectory + "\\Edit.cshtml";

            using (StreamReader template = new StreamReader(edit_source))
            using (StreamWriter output = new StreamWriter(target))
            {
                while (template.Peek() >= 0)
                {
                    string buffer = template.ReadLine();

                    buffer = buffer.Replace(Resources.NamespaceBal, this.builderInfo.BusinessLayerNamespace);
                    buffer = buffer.Replace(Resources.Namespace, this.builderInfo.RootNamespace);
                    buffer = buffer.Replace(Resources.SelectedModel, this.builderInfo.SelectedModel);
                    buffer = buffer.Replace(Resources.SelectedModelSmallCaps, this.builderInfo.SelectedModel.ToLower());
                    buffer = buffer.Replace(Resources.Entity, pluralizationService.Pluralize(this.builderInfo.SelectedModel));
                    buffer = buffer.Replace(Resources.ViewBagFieldsTemplate, this.GenerateEditFieldsTemplate());
                    buffer = buffer.Replace(Resources.ViewBagLayoutTemplate, this.GenerateLayoutTemplate());

                    output.WriteLine(buffer);
                }
            }
        }
    }
}
